/** @file gui_stats.h
    @brief A stats page widget */

#ifndef G3_GUI_STATS_H
#define G3_GUI_STATS_H

#include "singleton.h"

#include "gui/gui.h"

namespace G3 {
namespace GUI {

/** @class STATS_ENTRY
    @brief An abstract stats entry class */
class STATS_ENTRY {
	public:
        /**
            @brief A constructor that sets the label and priority
            @param[in] aLabel Reference to the entry name
            @param[in] aPriority The priority or order number of the entry
        */
		STATS_ENTRY (const std::string &aLabel, int aPriority = 1);
		/**
            @brief A destructor
		*/
		virtual ~STATS_ENTRY () { Label.clear (); }

        /** Priority or order number of the entry */
		int Priority;
		/** Entry label string */
		std::string Label;

        /**
            @brief Attaches a font to this entry
            @param[in] aFont Pointer to the font
        */
		virtual void AttachFont (FONT *aFont) = 0;

        /**
            @brief Draws an entry - needed for integration into Stats
            @param[in] Position Reference to the drawing position on the screen
            @param[in] Highlighted Is this entry highlighted ?
            @param[in] aElapsedTime The elapsed time since the last call
        */
		virtual void Draw (const VEC2I &Position, bool Highlighted = false, float aElapsedTime = 0.0f) = 0;
};

/** @class STATS_LABEL
    @brief A simple text label stats entry */
class STATS_LABEL: public STATS_ENTRY {
    public:
        /**
            @brief Constructor that sets the label and priority
            @param[in] aLabel Reference to the label string
            @param[in] aPriority Priority of the entry
        */
		STATS_LABEL (const std::string &aLabel, int aPriority = 1);
		/**
            @brief A destructor
		*/
		~STATS_LABEL ();

        /** The label line */
		LABEL Line;

        /**
            @brief Attaches a font to the entry
            @param[in] aFont pointer to the new font
        */
		void AttachFont (FONT *aFont);

        /**
            @brief Draws the entry
            @param[in] Position Reference to the drawing position on the screen
            @param[in] Highlighted Is this entry highlighted ?
            @param[in] aElapsedTime The elapsed time since the last call
        */
		void Draw (const VEC2I &Position, bool Highlighted = false, float aElapsedTime = 0.0f);
};

/** @class STATS_INT_PTR
    @brief An integer observer stats entry */
class STATS_INT_PTR: public STATS_ENTRY {
	public:
        /**
            @brief Constructor that sets the label, pointer and priority
            @param[in] aLabel Reference to the label string
            @param[in] aValue Pointer to the observed integer
            @param[in] aPriority Priority of the entry
        */
		STATS_INT_PTR (const std::string &aLabel, int *aValue = NULL, int aPriority = 1);
		/**
            @brief A destructor
		*/
		~STATS_INT_PTR ();

        /** Pointer to the observed integer */
		int *Value;
        /** Is the range of the integer limited (when the user changes it via the stats entry) */
		bool RangeUsed;
		/** Minimum value that is allowed for this integer */
		int MinValue;
		/** Maximum value allowed for this integer */
		int MaxValue;

        /** The label line */
		LABEL Line;

        /**
            @brief Attaches a font to the entry
            @param[in] aFont pointer to the new font
        */
		void AttachFont (FONT *aFont);

        /**
            @brief Draws the entry
            @param[in] Position Reference to the drawing position on the screen
            @param[in] Highlighted Is this entry highlighted ?
            @param[in] aElapsedTime The elapsed time since the last call
        */
		void Draw (const VEC2I &Position, bool Highlighted = false, float aElapsedTime = 0.0f);
};

/** @class STATS_FLOAT_PTR
    @brief A float observer stats entry */
class STATS_FLOAT_PTR: public STATS_ENTRY {
	public:
        /**
            @brief Constructor that sets the label, pointer and priority
            @param[in] aLabel Reference to the label string
            @param[in] aValue Pointer to the observed float
            @param[in] aPriority Priority of the entry
        */
		STATS_FLOAT_PTR (const std::string &aLabel, float *aValue = NULL, int aPriority = 1);
		/**
            @brief A destructor
		*/
		~STATS_FLOAT_PTR ();

        /** Pointer to the float to be observed */
		float *Value;
        /** Is the range of the float limited (when the user changes it via the stats entry) */
		bool RangeUsed;
		/** Minimum value that is allowed for this float */
		float MinValue;
		/** Maximum value allowed for this float */
		float MaxValue;

        /** The label line */
		LABEL Line;

        /**
            @brief Attaches a font to the entry
            @param[in] aFont pointer to the new font
        */
		void AttachFont (FONT *aFont);

        /**
            @brief Draws the entry
            @param[in] Position Reference to the drawing position on the screen
            @param[in] Highlighted Is this entry highlighted ?
            @param[in] aElapsedTime The elapsed time since the last call
        */
		void Draw (const VEC2I &Position, bool Highlighted = false, float aElapsedTime = 0.0f);
};

/** @class STATS_VEC3F_PTR
    @brief A vertex observer stats entry */
class STATS_VEC3F_PTR: public STATS_ENTRY {
	public:
        /**
            @brief Constructor that sets the label, pointer and priority
            @param[in] aLabel Reference to the label string
            @param[in] aValue Pointer to the observed vertex
            @param[in] aPriority Priority of the entry
        */
		STATS_VEC3F_PTR (const std::string &aLabel, VEC3F *aValue = NULL, int aPriority = 1);
		/**
            @brief A destructor
		*/
		~STATS_VEC3F_PTR ();

        /** Pointer to the vertex to be observed */
		VEC3F *Value;

        /** The label line */
		LABEL Line;

        /**
            @brief Attaches a font to the entry
            @param[in] aFont pointer to the new font
        */
		void AttachFont (FONT *aFont);

        /**
            @brief Draws the entry
            @param[in] Position Reference to the drawing position on the screen
            @param[in] Highlighted Is this entry highlighted ?
            @param[in] aElapsedTime The elapsed time since the last call
        */
		void Draw (const VEC2I &Position, bool Highlighted = false, float aElapsedTime = 0.0f);
};

/** @class STATS_ENTRY_PTR
    @brief A dummy class for sorting the entries */
class STATS_ENTRY_PTR {
	public:
        /**
            @brief A constructor that sets the entry pointer
            @param[in] aEntry Pointer to the stats entry
        */
		STATS_ENTRY_PTR (STATS_ENTRY *aEntry = NULL);
		/**
            @brief Destructor
		*/
		~STATS_ENTRY_PTR () { pEntry = NULL; }

        /** Pointer to the entry */
		STATS_ENTRY *pEntry;

        /**
            @brief Assignment operator
            @param[in] e Reference to the other entry pointer dummy to be copied
            @return Reference to the freshly copied class
        */
		STATS_ENTRY_PTR& operator= (const STATS_ENTRY_PTR &e);

        /**
            @brief Less than operator - helper for sorting
            @param[in] e Reference to the other entry pointer
            @return True if 'this' is less than the 'e', false otherwise
        */
		bool operator< (const STATS_ENTRY_PTR &e) const;
};

/** @class STATS_PAGE
    @brief A stats page class */
class STATS_PAGE {
	public:
        /**
            @brief Constructor that sets the font, label, rectangle and priority
            @param[in] aFont Pointer to the font
            @param[in] aLabel Reference to the label string
            @param[in] aRect Reference to the stats page group rectangle
            @param[in] aPriority Priority of the entry
        */
		STATS_PAGE (FONT *aFont, const std::string &aLabel, const RECTI &aRect, int aPriority = 1);
		/**
            @brief Simply a destructor
		*/
		~STATS_PAGE ();

        /** The priority of this stats page (page number) */
		int Priority;
		/** A set of stats entries */
		std::multiset<STATS_ENTRY_PTR> Entries;
		/** Iterator to the current entry */
		std::multiset<STATS_ENTRY_PTR>::iterator CurrentEntry;
		/** Are the stats editable ? \todo Implement stat editing - simple editboxes instead of just labels */
		bool Editable;

		/** Pointer to the font */
		FONT *Font;
		/** The group around the entries */
		GROUP Group;

        /**
            @brief Assignment operator
            @param[in] aPage Reference to the page to be copied
            @return Reference to the freshly copied page
        */
		STATS_PAGE& operator= (const STATS_PAGE &aPage);

        /**
            @brief Adds an entry
            @param[in] aEntry Pointer to the entry to be added
        */
		void AddEntry (STATS_ENTRY *aEntry);

        /**
            @brief Sets the caption or title of the page
            @param[in] aCaption Reference to the caption or title string
        */
		void SetCaption (const std::string &aCaption);

		/**
            @brief Attaches a font to this page
            @param[in] aFont Pointer to the font to be used
		*/
		void AttachFont (FONT *aFont);

        /**
            @brief Clears the page from all entries
        */
		void Clear ();

        /**
            @brief Renders the page
            @param[in] aElapsedTime Elapsed time since the last call
        */
		void Draw (float aElapsedTime = 0.0f);
};

/** @class STATS_PAGE_PTR
    @brief A dummy class used for sorting the stats pages */
class STATS_PAGE_PTR {
	public:
        /**
            @brief A constructor that sets the page pointer
            @param[in] aPage Pointer to the page
        */
		STATS_PAGE_PTR (STATS_PAGE *aPage = NULL);
		/**
            @brief Destructor
		*/
		~STATS_PAGE_PTR () { pPage = NULL; }

        /** The page pointer */
		STATS_PAGE *pPage;

        /**
            @brief Assignment operator
            @param[in] p Reference to the stats page pointer dummy to be copied
            @return Reference to the fresh dummy-clone
        */
		STATS_PAGE_PTR& operator= (const STATS_PAGE_PTR &p);

        /**
            @brief Less than operator - helper for sorting
            @param[in] p Reference to the other stats page pointer
            @return True if 'this' is less than the 'p', false otherwise
        */
		bool operator< (const STATS_PAGE_PTR &p) const;
};

/** @class STATS
    @brief The multipaged stats widget singleton */
class STATS: public G3::GUI::WIDGET, public SINGLETON<STATS> {
	public:
        /**
            @brief A constructor
        */
		STATS ();
        /**
            @brief A destructor
        */
		~STATS ();

        /** A set of stats pages */
		std::multiset<STATS_PAGE_PTR> Pages;
		/** Iterator to the current page */
		std::multiset<STATS_PAGE_PTR>::iterator CurrentPage;

        /**
            @brief Adds a page
            @param[in] aPage Pointer to the page to be added
        */
		void AddPage (STATS_PAGE *aPage);

        /**
            @brief Takes the next page
        */
		void NextPage ();
		/**
            @brief Takes the previous page
		*/
		void PreviousPage ();

        /**
            @brief Attaches a new font to the stats pages
            @param[in] aFont Pointer to the new font
        */
		void AttachFont (FONT *aFont);

        /**
            @brief Clears the pages
        */
		void Clear ();

        /**
            @brief Renders the stats widget
            @param[in] aElapsedTime Elapsed time since the last call
        */
		void Draw (float aElapsedTime = 0.0f);

        /**
            @brief Gets the type of this widget
            @return The type index \see TYPE_MANAGER
        */
		uint GetType () { return MainTypeMgr.GetType ("W_STATS"); }

        /**
            @brief Is this widget static ?
            @return False.
        */
		virtual bool IsStatic () { return true; }
};

/** The main stats singleton instance */
extern STATS MainStats;

}
}

#endif

